package indy.test.mh;

import indy.test.BlackBoxTest;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;

@BlackBoxTest
public class FastAndSlow {
    private static final Lookup LOOKUP = MethodHandles.lookup();

    // ----

    static Object fastAdd(int x, int y) {
        int z = x+y;
        if ((x ^ y) >= 0 && (x ^ z) < 0) {
            System.out.println("oops, it's overflowing");
            return slowAdd(x, y);
        }
        return z;
    }

    // ----

    static Object slowAdd(Object x, Object y) {
        double xd = ((Number)x).doubleValue();
        double yd = ((Number)y).doubleValue();
        System.out.println("I'm hungry; is it done yet?");
        return xd + yd;
    }

    // ----

    static boolean bothInts(Object x, Object y) {
        return x instanceof Integer && y instanceof Integer;
    }

    public static void main(String... av) throws Throwable {
        MethodHandle fastAdd =
            LOOKUP.findStatic(FastAndSlow.class, "fastAdd",
                    MethodType.methodType(Object.class, int.class, int.class));
        MethodHandle slowAdd =
            LOOKUP.findStatic(FastAndSlow.class, "slowAdd",
                    MethodType.methodType(Object.class, Object.class, Object.class));
        MethodHandle bothInts =
            LOOKUP.findStatic(FastAndSlow.class, "bothInts",
                    MethodType.methodType(boolean.class, Object.class, Object.class));
        fastAdd = fastAdd.asType(slowAdd.type());
        
        MethodHandle combo = MethodHandles.guardWithTest(bothInts, fastAdd, slowAdd);
        System.out.println(combo.invoke(2, 3));
        System.out.println(combo.invoke(2.1, 3.1));
        System.out.println(combo.invoke(Integer.MAX_VALUE, -1));
        System.out.println(combo.invoke(Integer.MAX_VALUE, 1));
    }
}
